package com.tools.web.interceptor.auth;

import com.tools.common.io.CharsetEnum;
import com.tools.common.object.Note;
import com.tools.common.security.secret.*;
import com.tools.web.interceptor.access.AccessSource;

import java.util.Map;
import java.util.Objects;

/**
 * 身份认证过滤器的配置项包装类
 * */
@Note("身份认证过滤器的配置项包装类")
public class AuthSource {

    @Note("token 是否在请求头中。false 的话就从请求参数中获取")
    private boolean tokenFromHeader;

    @Note("token 的名称")
    private String tokenName;

    @Note("【AuthToken 的规范】: 组成 token 各个部分的分隔符")
    private String tokenSeparator;

    @Note("加密解密的 Cipher 实例和操作的包装类")
    private Cypher cypher;

    @Note("缓存 AuthUser key 的前缀")
    private String cacheKeyPrefix;

    @Note("设备类型 ID 与可允许同时在线的设备的最大数量映射。" +
            "这里以对象类型 JSON 字符串的形式读取。" +
            "设备类型 ID 参考本包的 LoginDeviceTypeEnum 的 ID。")
    private String deviceTypeIdAndMaxTotalJsonString;

    @Note("【异常 JSON 信息】: 没有获取到 token")
    private String tokenNotFoundErrorJson;

    @Note("【异常 JSON 信息】: token 不符合 AuthToken 的规范解析失败")
    private String tokenParseFailedErrorJson;

    @Note("【异常 JSON 信息】: token 已过期")
    private String tokenExpiredJson;

    @Note("token 续期工具实例")
    private TokenExtender tokenExtender;

    @Note("若直接在认证管理器开启授权检查，则这里就是授权管理器的全路径类名")
    private String accessManagerClassName;

    @Note("若开启授权检查，则此处是授权管理器的配置项包装类")
    private AccessSource accessSource;

    /* **************************************************************************************
     *
     *          构造器
     *
     * **************************************************************************************
     * */

    public AuthSource() {}

    public static AuthSource of() {
        return new AuthSource();
    }

    /* **************************************************************************************
     *
     *          Getter/Setter
     *
     * **************************************************************************************
     * */

    public boolean isTokenFromHeader() {
        return tokenFromHeader;
    }

    public void setTokenFromHeader(Boolean tokenFromHeader) {
        this.tokenFromHeader = tokenFromHeader != null && tokenFromHeader;
    }

    public String getTokenName() {
        if(tokenName == null || tokenName.isEmpty()) throw new NullPointerException("token 名称为空");
        return tokenName;
    }

    public void setTokenName(String tokenName) {
        this.tokenName = tokenName;
    }

    public String getTokenSeparator() {
        return tokenSeparator;
    }

    public void setTokenSeparator(String tokenSeparator) {
        this.tokenSeparator = tokenSeparator;
    }

    public Cypher getCypher() {
        if(cypher == null) throw new NullPointerException("token 的加密工具为 null");
        return cypher;
    }

    public void setCypher(Cypher cypher) {
        this.cypher = cypher;
    }

    public String getCacheKeyPrefix() {
        return cacheKeyPrefix;
    }

    public void setCacheKeyPrefix(String cacheKeyPrefix) {
        this.cacheKeyPrefix = cacheKeyPrefix;
    }

    public String getDeviceTypeIdAndMaxTotalJsonString() {
        return deviceTypeIdAndMaxTotalJsonString;
    }

    public void setDeviceTypeIdAndMaxTotalJsonString(String deviceTypeIdAndMaxTotalJsonString) {
        this.deviceTypeIdAndMaxTotalJsonString = deviceTypeIdAndMaxTotalJsonString;
    }

    public String getTokenNotFoundErrorJson() {
        if(tokenNotFoundErrorJson == null || tokenNotFoundErrorJson.isEmpty()) throw new NullPointerException("异常 JSON 信息为空");
        return tokenNotFoundErrorJson;
    }

    public void setTokenNotFoundErrorJson(String tokenNotFoundErrorJson) {
        this.tokenNotFoundErrorJson = tokenNotFoundErrorJson;
    }

    public String getTokenParseFailedErrorJson() {
        if(tokenParseFailedErrorJson == null || tokenParseFailedErrorJson.isEmpty()) throw new NullPointerException("异常 JSON 信息为空");
        return tokenParseFailedErrorJson;
    }

    public void setTokenParseFailedErrorJson(String tokenParseFailedErrorJson) {
        this.tokenParseFailedErrorJson = tokenParseFailedErrorJson;
    }


    public String getTokenExpiredJson() {
        if(tokenExpiredJson == null || tokenExpiredJson.isEmpty()) throw new NullPointerException("异常 JSON 信息为空");
        return tokenExpiredJson;
    }

    public void setTokenExpiredJson(String tokenExpiredJson) {
        this.tokenExpiredJson = tokenExpiredJson;
    }

    public TokenExtender getTokenExtender() {
        return tokenExtender;
    }

    public void setTokenExtender(TokenExtender tokenExtender) {
        this.tokenExtender = tokenExtender;
    }

    public String getAccessManagerClassName() {
        return accessManagerClassName;
    }

    public void setAccessManagerClassName(String accessManagerClassName) {
        this.accessManagerClassName = accessManagerClassName;
    }

    public AccessSource getAccessSource() {
        return accessSource;
    }

    public void setAccessSource(AccessSource accessSource) {
        this.accessSource = accessSource;
    }

    @Override
    public String toString() {
        return "AuthSource{" +
                "tokenFromHeader=" + tokenFromHeader +
                ", tokenName='" + tokenName + '\'' +
                ", tokenSeparator='" + tokenSeparator + '\'' +
                ", cypher=" + cypher +
                ", cacheKeyPrefix='" + cacheKeyPrefix + '\'' +
                ", accessManagerClassName='" + accessManagerClassName + '\'' +
                ", deviceTypeIdAndMaxTotalJsonString='" + deviceTypeIdAndMaxTotalJsonString + '\'' +
                ", tokenNotFoundErrorJson='" + tokenNotFoundErrorJson + '\'' +
                ", tokenParseFailedErrorJson='" + tokenParseFailedErrorJson + '\'' +
                ", tokenExpiredJson='" + tokenExpiredJson + '\'' +
                ", tokenExtender=" + tokenExtender +
                ", accessSource=" + accessSource +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        AuthSource that = (AuthSource) o;
        return tokenFromHeader == that.tokenFromHeader && Objects.equals(tokenName, that.tokenName) && Objects.equals(tokenSeparator, that.tokenSeparator) && Objects.equals(cypher, that.cypher) && Objects.equals(cacheKeyPrefix, that.cacheKeyPrefix) && Objects.equals(deviceTypeIdAndMaxTotalJsonString, that.deviceTypeIdAndMaxTotalJsonString) && Objects.equals(tokenNotFoundErrorJson, that.tokenNotFoundErrorJson) && Objects.equals(tokenParseFailedErrorJson, that.tokenParseFailedErrorJson) && Objects.equals(tokenExpiredJson, that.tokenExpiredJson) && Objects.equals(tokenExtender, that.tokenExtender) && Objects.equals(accessManagerClassName, that.accessManagerClassName) && Objects.equals(accessSource, that.accessSource);
    }

    @Override
    public int hashCode() {
        return Objects.hash(tokenFromHeader, tokenName, tokenSeparator, cypher, cacheKeyPrefix, deviceTypeIdAndMaxTotalJsonString, tokenNotFoundErrorJson, tokenParseFailedErrorJson, tokenExpiredJson, tokenExtender, accessManagerClassName, accessSource);
    }

    /* **************************************************************************************
     *
     *          链式调用
     *
     * **************************************************************************************
     * */

    public AuthSource tokenFromHeader(Boolean tokenFromHeader) {
        this.setTokenFromHeader(tokenFromHeader);
        return this;
    }

    public AuthSource tokenName(String tokenName) {
        this.setTokenName(tokenName);
        return this;
    }

    public AuthSource tokenSeparator(String tokenSeparator) {
        this.setTokenSeparator(tokenSeparator);
        return this;
    }

    public AuthSource cypher(Cypher cypher) {
        this.setCypher(cypher);
        return this;
    }

    public AuthSource cacheKeyPrefix(String cacheKeyPrefix) {
        this.setCacheKeyPrefix(cacheKeyPrefix);
        return this;
    }

    public AuthSource deviceTypeIdAndMaxTotalJsonString(String deviceTypeIdAndMaxTotalJsonString) {
        this.setDeviceTypeIdAndMaxTotalJsonString(deviceTypeIdAndMaxTotalJsonString);
        return this;
    }

    public AuthSource tokenNotFoundErrorJson(String tokenNotFoundErrorJson) {
        this.setTokenNotFoundErrorJson(tokenNotFoundErrorJson);
        return this;
    }

    public AuthSource tokenParseFailedErrorJson(String tokenParseFailedErrorJson) {
        this.setTokenParseFailedErrorJson(tokenParseFailedErrorJson);
        return this;
    }

    public AuthSource tokenExpiredJson(String tokenExpiredJson) {
        this.setTokenExpiredJson(tokenExpiredJson);
        return this;
    }

    public AuthSource tokenExtender(TokenExtender tokenExtender) {
        this.setTokenExtender(tokenExtender);
        return this;
    }

    public AuthSource accessManagerClassName(String accessManagerClassName) {
        this.setAccessManagerClassName(accessManagerClassName);
        return this;
    }


    public AuthSource accessSource(AccessSource accessSource) {
        this.setAccessSource(accessSource);
        return this;
    }

    public static Cypher buildCypherByConfig(Map<String, Object> config) {
        String algorithm = (String) config.get("auth-interceptor-token-secret-algorithm");
        if(algorithm == null || algorithm.isEmpty()) {
            throw new NullPointerException("AuthToken 的加解密需要指定算法和密钥。目前支持（SM4、SM2、AES、RSA）");
        }
        if("SM4".equalsIgnoreCase(algorithm)) {
            String secretKey = (String) config.get("auth-interceptor-token-secret-key");
            if(secretKey == null || secretKey.isEmpty()) {
                secretKey = SecretKit.createSM4Key();
            }
            return new SM4Cypher(secretKey, CharsetEnum.UTF_8);
        }
        if("AES".equalsIgnoreCase(algorithm)) {
            String secretKey = (String) config.get("auth-interceptor-token-secret-key");
            if(secretKey == null || secretKey.isEmpty()) {
                secretKey = SecretKit.createAES128BitKey();
            }
            return new AESCypher(secretKey, CharsetEnum.UTF_8);
        }
        if("SM2".equalsIgnoreCase(algorithm)) {
            String privateKey = (String) config.get("auth-interceptor-token-secret-private-key");
            String publicKey = (String) config.get("auth-interceptor-token-secret-public-key");
            return new SM2Cypher(publicKey, privateKey);
        }
        if("RSA".equalsIgnoreCase(algorithm)) {
            String privateKey = (String) config.get("auth-interceptor-token-secret-private-key");
            String publicKey = (String) config.get("auth-interceptor-token-secret-public-key");
            return new RSACypher(publicKey, privateKey);
        }
        throw new IllegalArgumentException("AuthToken 的加解密暂不支持除 SM4、SM2、AES、RSA 以外的算法支持");
    }
}
